// +build linux

package iouring_syscall

import (
	"os"
	"syscall"
	"unsafe"
)

const (
	IOURING_SETUP    = 425
	IOURING_ENTER    = 426
	IOURING_REGISTER = 427
)

// io_uring_setup flags
const (
	IORING_SETUP_IOPOLL uint32 = 1 << iota
	IORING_SETUP_SQPOLL
	IORING_SETUP_SQ_AFF
	IORING_SETUP_CQSIZE
	IORING_SETUP_CLAMP
	IORING_SETUP_ATTACH_WQ
	IORING_SETUP_R_DISABLED
)

// io_uring_params->features flags
const (
	IORING_FEAT_SINGLE_MMAP uint32 = 1 << iota
	IORING_FEAT_NODROP
	IORING_FEAT_SUBMIT_STABLE
	IORING_FEAT_RW_CUR_POS
	IORING_FEAT_CUR_PERSONALITY
	IORING_FEAT_FAST_POLL
	IORING_FEAT_POLL_32BITS
	IORING_FEAT_SQPOLL_NONFIXED
	IORING_FEAT_EXT_ARG
	IORING_FEAT_NATIVE_WORKERS
	IORING_FEAT_RSRC_TAGS
)

// IOURingParams ...
type IOURingParams struct {
	SQEntries    uint32
	CQEntries    uint32
	Flags        uint32
	SQThreadCPU  uint32
	SQThreadIdle uint32
	Features     uint32
	WQFd         uint32
	Resv         [3]uint32

	SQOffset SQRingOffset
	CQOffset CQRingOffset
}

// SQRingOffset ...
type SQRingOffset struct {
	Head        uint32
	Tail        uint32
	RingMask    uint32
	RingEntries uint32
	Flags       uint32
	Dropped     uint32
	Array       uint32
	Resv1       uint32
	Resv2       uint64
}

// CQRingOffset ...
type CQRingOffset struct {
	Head        uint32
	Tail        uint32
	RingMask    uint32
	RingEntries uint32
	Overflow    uint32
	Cqes        uint32
	Flags       uint32
	Resv1       uint32
	Resv2       uint64
}

// int io_uring_setup(unsigned int entries, struct io_uring_params *p)
// IOURingSetup ...
func IOURingSetup(entries uint, params *IOURingParams) (int, error) {
	res, _, errno := syscall.RawSyscall(
		IOURING_SETUP,
		uintptr(entries),
		uintptr(unsafe.Pointer(params)),
		0,
	)
	if errno != 0 {
		return int(res), os.NewSyscallError("iouring_setup", errno)
	}

	return int(res), nil
}
